/*
 * Copyright 2007-2010 Jeremy Brown.
 *
 * Licensed under the Apache License, Version 2.0 (the "License")
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @author <a href="http://jeremy-brown.com">Jeremy Brown</a>
 */


package groovy.prefuse.factory

import groovy.prefuse.*
import groovy.prefuse.impl.action.*

import prefuse.action.*
import prefuse.Visualization

public class ActionFactory extends AbstractFactory
{
	private Class klass

	public ActionFactory()
	{
	}
	
	public ActionFactory(Class klass)
	{
		this.klass = klass
	}

	boolean isLeaf()
	{
		return false
	}
	    
    public Object newInstance(FactoryBuilderSupport builder, Object name, Object value, Map attributes) throws InstantiationException, IllegalAccessException
	{
		builder.context.put("name", attributes.remove("name")) //Action will be added to Visualization with this name

		if(value == null && attributes.action)
		{
			value = attributes.remove("action")
		}
		
		if(value instanceof Action)
		{
			return value
		}
		
		def buildClass
		if(klass)
		{
			buildClass = klass
		}
		else if(value instanceof Class)
		{
			buildClass = value
			value = null
		}

		
		def action = null
		
		if(buildClass instanceof Class && Action.isAssignableFrom(buildClass))
		{
			if(RepaintAction.equals(buildClass))
			{
				action = new RepaintAction()
			}
			else if(GroupAction.equals(buildClass))
			{
				if(attributes.closure)
				{
					action = new ClosureGroupAction(attributes.remove("closure"))
				}
				else if(attributes.run)
				{
					action = new ClosureGroupAction(attributes.remove("run"))
				}
			}
			else if(ItemAction.equals(buildClass))
			{
				//give 2 ways to refer to the closure: closure or process
				def closure
				if(attributes.closure){closure = attributes.remove("closure")}
				else if(attributes.process){closure = attributes.remove("process")}
				
				//give 2 ways to refer to the filterPredicate: predicate or filterPredicate (because most Prefuse classes use setPredicate, but ItemAction uses setFilterPredicate.
				if(attributes.predicate){attributes.filterPredicate = attributes.remove("predicate")}
				
				if(closure)
				{
					action = new ClosureItemAction(closure)
				}
			}
			else
			{
				//Try to instantiate the Action with a no-parameter-constructor
				action = buildClass.newInstance()
			}
		}
		//If pfAction(...) is called with just a closure: or run: attribute, create a ClosureAction
		else if(attributes.closure || attributes.run)
		{
			if(attributes.closure)
			{
				action = new ClosureAction(attributes.remove("closure"))
			}
			else if(attributes.run)
			{
				action = new ClosureAction(attributes.remove("run"))
			}
		}

		return action
	}

	public void setParent(FactoryBuilderSupport builder, Object parent, Object child) 
	{
		if(child instanceof CompositeAction ||
			parent.class.isAssignableFrom(child.class))
		{
			//Don't add a composite action until it is completed (in onNodeCompleted)
			//This also covers options like ColorAction where one ColorAction can be added to another
			return
		}
		
		addNodeToParent(builder, parent, child)
    }
	
	public void onNodeCompleted(FactoryBuilderSupport builder, Object parent, Object child) 
	{
		if(child instanceof CompositeAction ||
				parent.class.isAssignableFrom(child.class))
		{
			addNodeToParent(builder, parent, child)
		}
    }
	
	public void addNodeToParent(FactoryBuilderSupport builder, Object parent, Object child)
	{
		if(parent instanceof Visualization)
		{
			parent.putAction(builder.context.name, child)
		}
		else if(parent instanceof CompositeAction)
		{
			parent.add(child)
		}
		else if(parent.class.isAssignableFrom(child.class))
		{
			//This covers options like ColorAction where one ColorAction can be added to another
			try
			{
				parent.add(builder.context.predicate, child)
			}
			catch(Exception e){}
		}
	}
}
